package app.purchase.a571xz.com.myandroidframe.repository;

import com.trello.rxlifecycle2.LifecycleTransformer;

import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

import app.purchase.a571xz.com.myandroidframe.httpservice.retrofit.ApiService;
import app.purchase.a571xz.com.myandroidframe.httpservice.retrofit.RetrofitService;
import io.reactivex.Flowable;
import io.reactivex.FlowableSubscriber;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subscribers.ResourceSubscriber;
import rx.Subscriber;

/**
 * 网络请求数据资源库
 */
public class NetworkRepository {
    //是否开启失败重试功能
    private static final boolean IS_USE_RETRY_WHEN_ERROR = false;

    //重试间隔时间
    private static final int TIME_RETRY_DELAY = 3;

    //重试次数
    private static final int MAX_RETRY_COUNT = 3;

    private static NetworkRepository networkRepository;

    public static NetworkRepository getInstance() {
        if (networkRepository == null) {
            synchronized (NetworkRepository.class) {
                if (networkRepository == null)
                    networkRepository = new NetworkRepository();
            }
        }
        return networkRepository;
    }

    /**
     * 获取指定的网络请求Api接口
     *
     * @param serviceClass ApiService的类型
     * @return 相应的ApiService
     */
    public <T> T getService(Class<T> serviceClass) {
        return RetrofitService.getBaseApi(serviceClass);
    }

    public ApiService getService() {
        return RetrofitService.getApi();
    }


    /**
     * 普通的网络api请求，会根据全局配置判断是否使用失败重试机制
     *
     * @param observable  请求
     * @param observer    请求回调
     * @param transformer 生命周期控制，如果为null，则不进行生命周期控制
     */
    public void commonRequest(Flowable observable, ResourceSubscriber observer, LifecycleTransformer transformer) {
        handleRetry(handleThread(handleLife(observable, transformer)), IS_USE_RETRY_WHEN_ERROR, TIME_RETRY_DELAY, MAX_RETRY_COUNT).subscribe
                (observer);
    }

    /**
     * 普通的网络api请求，会根据所传参数来使用失败重试机制
     *
     * @param observable     请求
     * @param observer       请求回调
     * @param transformer    生命周期控制，如果为null，则不进行生命周期控制
     * @param timeRetryDelay 失败后重试的延迟时长
     * @param maxRetryCount  失败后重试的最大次数
     */
    public void commonRequest(Flowable observable, ResourceSubscriber observer, LifecycleTransformer transformer, int timeRetryDelay, int maxRetryCount) {
        handleRetry(handleThread(handleLife(observable, transformer)), true, timeRetryDelay, maxRetryCount).subscribe(observer);
    }

    //处理网络请求的生命周期控制
    private Flowable handleLife(Flowable observable, LifecycleTransformer transformer) {
        if (transformer != null) {
            observable.compose(transformer);
        }
        return observable;
    }

    //处理线程调度
    private Flowable handleThread(Flowable observable) {
        return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    }

    //处理失败重试机制
    private Flowable handleRetry(Flowable observable, boolean isUseRetry, int timeRetryDelay, int maxRetryCount) {
        if (isUseRetry) {
            return observable.retryWhen(new RetryFunction(timeRetryDelay >= 0 ? timeRetryDelay : TIME_RETRY_DELAY, maxRetryCount > 0 ? maxRetryCount : MAX_RETRY_COUNT));
        } else {
            return observable;
        }
    }

    class RetryFunction implements Function<Observable<Throwable>, ObservableSource<?>> {

        private int retryDelaySeconds;//延迟重试的时间
        private int retryCountMax;//最大重试次数
        private int retryCount;//记录当前重试次数

        public RetryFunction(int retryDelaySeconds, int retryCountMax) {
            this.retryDelaySeconds = retryDelaySeconds;
            this.retryCountMax = retryCountMax;
        }

        @Override
        public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
            //方案一：使用zip控制重试次数，重试3次后不再重试（会隐式回调onComplete结束请求，但我需要的是回调onError，所以没采用方案一）
//            return Observable.zip(throwableObservable,Observable.range(1, retryCountMax),new BiFunction<Throwable, Integer, Throwable>() {
//                @Override
//                public Throwable apply(Throwable throwable, Integer integer) throws Exception {
//                    RingLog.e("ljy",""+integer);
//                    return throwable;
//                }
//            }).flatMap(new Function<Throwable, ObservableSource<?>>() {
//                @Override
//                public ObservableSource<?> apply(Throwable throwable) throws Exception {
//                    if (throwable instanceof UnknownHostException) {
//                        return Observable.error(throwable);
//                    }
//                    return Observable.timer(retryDelaySeconds, TimeUnit.SECONDS);
//                }
//            });


            //方案二：使用全局变量来控制重试次数，重试3次后不再重试，通过代码显式回调onError结束请求
            return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                @Override
                public ObservableSource<?> apply(Throwable throwable) throws Exception {
                    //如果失败的原因是UnknownHostException（DNS解析失败，当前无网络），则没必要重试，直接回调error结束请求即可
                    if (throwable instanceof UnknownHostException) {
                        return Observable.error(throwable);
                    }

                    //没超过最大重试次数的话则进行重试
                    if (++retryCount <= retryCountMax) {
                        //延迟retryDelaySeconds后开始重试
                        return Observable.timer(retryDelaySeconds, TimeUnit.SECONDS);
                    }

                    return Observable.error(throwable);
                }
            });
        }
    }

}
